/*******************************************************************************
 * Copyright (c) 2015, 2016 Bosch Software Innovations GmbH and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and Eclipse Distribution License v1.0 which accompany this distribution.
 *   
 * The Eclipse Public License is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * The Eclipse Distribution License is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *   
 * Contributors:
 * Bosch Software Innovations GmbH - Please refer to git log
 *******************************************************************************/
package org.eclipse.vorto.codegen.protobuf.templates

import java.util.List
import org.eclipse.vorto.core.api.model.datatype.Property
import org.eclipse.vorto.core.api.model.functionblock.FunctionblockModel
import org.eclipse.vorto.core.api.model.functionblock.Param
import org.eclipse.vorto.core.api.model.functionblock.PrimitiveParam
import org.eclipse.vorto.core.api.model.functionblock.RefParam
import org.eclipse.vorto.core.api.model.functionblock.ReturnObjectType
import org.eclipse.vorto.core.api.model.functionblock.ReturnPrimitiveType
import org.eclipse.vorto.core.api.model.functionblock.ReturnType
import org.eclipse.vorto.plugin.generator.InvocationContext
import org.eclipse.vorto.core.api.model.functionblock.ReturnDictonaryType

class ProtobufFBTemplate extends ProtobufTemplate<FunctionblockModel> {

	override getContent(FunctionblockModel element, InvocationContext context) {
		'''
			// Generated by Vorto from «element.namespace».«element.name»:«element.version»
			syntax = "proto3";
			
			package «element.namespace»;
			
			import "org/eclipse/vorto/meta.proto";
			
			«FOR reference : element.references»
			import "«reference.importedNamespace.toLowerCase.replace(".","/")».proto";
			«ENDFOR»
			
			
			message «element.name» {
				org.eclipse.vorto.Meta meta = 1;
				«IF element.functionblock.status != null»
				«element.name»Status status = 2;
				«ENDIF»
				
			}
			
			service «element.name» {
				
				«IF element.functionblock.operations != null»
					«FOR operation : element.functionblock.operations»
						«IF operation.description != null»//«operation.description»«ENDIF»
						rpc «operation.name»(«operation.name.toFirstUpper»Request) returns («operation.name.toFirstUpper»Response) {}
					«ENDFOR»
				«ENDIF»
				«IF element.functionblock.status != null»
				rpc getStatus(StatusRequest) returns (StatusResponse) {}
				«ENDIF»
			}
			
			«IF element.functionblock.operations != null»
				«FOR operation : element.functionblock.operations»
					«IF operation.params != null»
						message «operation.name.toFirstUpper»Request {
							«generateMessagePropertiesFromParams(operation.params)»
						}
					«ENDIF»
					message «operation.name.toFirstUpper»Response {
						«generateMessagePropertiesFromReturnType(operation.returnType)»
					}
				«ENDFOR»
			«ENDIF»
			
			«IF element.functionblock.status != null»
				message «element.name»Status {
					«generateMessageProperties(element.functionblock.status.properties)»
				}
				
				message StatusRequest {
					// empty
				}
				
				message StatusResponse {
					«generateMessageProperties(element.functionblock.status.properties)»
				}
			«ENDIF»
			
		'''
	}

	def generateMessageProperties(List<Property> properties) {
		'''
			«IF properties !== null»
				«var counter = 1»
				«FOR property : properties»
					«IF property.multiplicity»repeated «ENDIF»«type(property.type)» «property.name» = «counter++»;
				«ENDFOR»
			«ENDIF»
		'''
	}

	def generateMessagePropertiesFromReturnType(ReturnType returnType) {
		'''
			«IF returnType !== null && returnType instanceof ReturnPrimitiveType»
				«IF returnType.multiplicity»repeated «ENDIF»«toProtoPrimitive((returnType as ReturnPrimitiveType).returnType)» value = 1;
			«ENDIF»
			«IF returnType !== null && returnType instanceof ReturnObjectType»
				«IF returnType.multiplicity»repeated «ENDIF»«(returnType as ReturnObjectType).returnType.name» value = 1;
			«ENDIF»
			«IF returnType !== null && returnType instanceof ReturnDictonaryType»
				«IF returnType.multiplicity»repeated «ENDIF»map<string,string> value = 1;
			«ENDIF»
		'''
	}

	def generateMessagePropertiesFromParams(List<Param> params) {
		'''
			«IF params !== null»
				«var counter = 1»
				«FOR param : params»
					«IF param.multiplicity»repeated «ENDIF»«type(param)» «param.name» = «counter++»;
				«ENDFOR»
			«ENDIF»
		'''
	}

	
	
	def String type(Param param) {
		if (param instanceof PrimitiveParam) {
			return toProtoPrimitive((param as PrimitiveParam).getType);
		} else if (param instanceof RefParam){
			return (param as RefParam).getType().name
		} else {
			return "map<string,string>"
		}
	}
	
	
	
}
